#include "defs.h"
#include <stddef.h>  // 包含NULL定义


void assert(int cond, const char *msg) {
  if (!cond) {
    printf("assert failed: ");
    printf((char*)msg);  // 显式转换为char*以匹配函数声明
    printf("\n");
    panic("assertion failure");
  }
}

void test_physical_memory(void) {
  printf("Running physical memory test...\n");
  
  int a=count_free_pages();
  printf("a= %d\n",a);

  void *page1 = alloc_page();
  assert(page1 != NULL, "page1 allocation failed");
  
  int b=count_free_pages();
  printf("b= %d\n",b);

  void *page2 = alloc_page();
  assert(page2 != NULL, "page2 allocation failed");
  
  int b1=count_free_pages();
  printf("b1= %d\n",b1);

  assert(page1 != page2, "page1 and page2 should be different");
  assert(((uint64)page1 & 0xFFF) == 0, "page1 is not page-aligned");
  assert(((uint64)page2 & 0xFFF) == 0, "page2 is not page-aligned");

  // 测试页面读写
  *(int*)page1 = 0x12345678;
  assert(*(int*)page1 == 0x12345678, "page1 write/read failed");

  // 测试释放和重新分配
  free_page(page1);

  int c=count_free_pages();
  printf("c= %d\n",c);

  void *page3 = alloc_page();

  int d=count_free_pages();
  printf("d= %d\n",d);

  assert(page3 != NULL, "page3 allocation failed after free");

  free_page(page2);
  free_page(page3);
  
  printf("Physical memory test passed\n");
}

void test_pagetable(void) {
  printf("Running pagetable test...\n");
  
  pagetable_t pt = (pagetable_t)alloc_page();
  assert(pt != NULL, "failed to allocate root pagetable");
  memset(pt, 0, PGSIZE);

  uint64 va = 0x100000;  // 确保这个虚拟地址在用户空间范围内
  uint64 pa = (uint64)alloc_page();
  assert(pa != 0, "failed to allocate physical page for mapping");

  // 映射页面，使用正确的权限组合
  int perm = PTE_R | PTE_W | PTE_U | PTE_V;
  assert(mappages(pt, va, PGSIZE, pa, perm) == 0, "mappages failed");

  pte_t *pte = walk(pt, va, 0);
  assert(pte != NULL, "walk failed to find pte");
  assert((*pte & PTE_V) != 0, "pte is not valid");
  assert(PTE2PA(*pte) == pa, "pte physical address mismatch");
  assert((*pte & (PTE_R | PTE_W | PTE_U)) == (PTE_R | PTE_W | PTE_U), "pte permissions incorrect");

  uint64 addr = walkaddr(pt, va);
  assert(addr == pa, "walkaddr returned wrong physical address");

  free_page((void*)pa);
  free_page(pt);
  
  printf("Pagetable test passed\n");
}

void test_virtual_memory(void) {
  printf("Before enabling paging...\n");

  kvminit();
  kvminithart();

  printf("After enabling paging...\n");

  // 测试内核数据访问
  int x = 42;
  assert(x == 42, "kernel data access failed after paging");

  // 测试内核地址空间访问（使用安全的地址）
  uint64 test_addr = KERNBASE + PGSIZE;  // 使用内核区域的安全地址
  *(int*)test_addr = 0xdeadbeef;
  assert(*(int*)test_addr == 0xdeadbeef, "kernel memory write/read failed");

  printf("Virtual memory test passed\n");
}
